// Copyright (C) 2011 by Christopher Diggins	
// Usage is permitted under the terms of the MIT License 1.0. 	

/** \file 
	Contains implementation of the array functions.
	\see \ref array
*/

/** Creates a new array. */
Array* array_new(int sz) {	
	Array* a = calloc(1, sizeof(Array));
	a->sz = sz;
	return a;
}

/** Frees the data of an array. */
void array_clear(Array* a) {
	a->cnt = 0;
	a->cap = 0;
	if (a->data) free(a->data);
	a->data = NULL;	
}

/** Frees an array, and the data it points to. */
void array_free(Array* a) {
	array_clear(a);
	free(a);
}

/** Initializes a new array value. */
Array* array_init(Array* a, int sz) {	
	a->sz = sz;
	a->cap = 0;
	a->cnt = 0;
	a->data = 0;
	return a;
}

/** Allocates space equal to "cap" (capacity). */
void array_alloc(Array* a, int cap) {
	assert(a->sz > 0);
	if (cap <= a->cap) return;
	a->data = (byte*)calloc(cap, a->sz);
	a->cap = cap;
}

/** Pushes a value onto the array. */
void array_push(Array* a, void* src, uint size) {	
	byte* dest; 
	assert(size == a->sz);
	if (a->cnt >= a->cap) 
		array_grow(a);
	dest = a->data + (a->cnt * a->sz);
	memcpy(dest, src, a->sz); 
	a->cnt++;
}

/** Increases the capacity of an array allocating more memory and copying old values. */
void array_grow(Array* a) {	
	if (!a->data) {
		array_alloc(a, ARRAY_MIN_SIZE);
	}
	else {
		byte* tmp = a->data;
		array_alloc(a, a->cap << 1);
		memcpy(a->data, tmp, a->cnt * a->sz);
		free(tmp);
	}
}

/** Clones the values of an array. */
Array* array_clone(Array* a) {
	Array* r = array_new(a->sz);
	array_alloc(r, a->cnt);
	assert(array_num_bytes(a) == array_num_bytes(r));
	memcpy(r, a, array_num_bytes(r));
	return r;
}